
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "uart.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#ifdef	USE_UART1
static RING_BUF gRingBuf1 = {0,};
#endif /* USE_UART1 */
#ifdef	USE_UART2
static RING_BUF gRingBuf2 = {0,};
#endif /* USE_UART2 */
#ifdef	USE_UART3
static RING_BUF gRingBuf3 = {0,};
#endif /* USE_UART3 */
static fxPKTPARSING gFxUart1Parsing = NULL;
static fxPKTPARSING gFxUart2Parsing = NULL;


/* Private function prototypes -----------------------------------------------*/
static void irqHandler(USART_TypeDef *pUSARTx, PRING_BUF pRB);
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

/* Private functions ---------------------------------------------------------*/
void Uart_Init(fxPKTPARSING fxUart1Parsing, fxPKTPARSING fxUart2Parsing)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
#ifdef	USE_UART1
	/* Enable GPIO clock */
	RCC_AHBPeriphClockCmd(UART1_TX_CLK | UART1_RX_CLK, ENABLE);

	/* Enable USART clock */
	RCC_APB2PeriphClockCmd(UART1_CLK, ENABLE);

	/* Connect PXx to USARTx_Tx */
	GPIO_PinAFConfig(UART1_TX_PORT, UART1_TX_SOURCE, UART1_TX_AF);

	/* Connect PXx to USARTx_Rx */
	GPIO_PinAFConfig(UART1_RX_PORT, UART1_RX_SOURCE, UART1_RX_AF);

	/* Configure USART Tx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = UART1_TX_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(UART1_TX_PORT, &GPIO_InitStructure);

	/* Configure USART Rx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = UART1_RX_PIN;
	GPIO_Init(UART1_RX_PORT, &GPIO_InitStructure);

	/* USART configuration */
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART1, &USART_InitStructure);

	/* Enable USART */
	USART_Cmd(USART1, ENABLE);

	/* Enable the USART Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	gRingBuf1.RxCRCnt = 0;
	gFxUart1Parsing = fxUart1Parsing;
#endif /* USE_UART1 */

#ifdef	USE_UART2
	/* Enable GPIO clock */
	RCC_AHBPeriphClockCmd(UART2_TX_CLK | UART2_RX_CLK, ENABLE);

	/* Enable USART clock */
	RCC_APB1PeriphClockCmd(UART2_CLK, ENABLE);

	/* Connect PXx to USARTx_Tx */
	GPIO_PinAFConfig(UART2_TX_PORT, UART2_TX_SOURCE, UART2_TX_AF);

	/* Connect PXx to USARTx_Rx */
	GPIO_PinAFConfig(UART2_RX_PORT, UART2_RX_SOURCE, UART2_RX_AF);

	/* Configure USART Tx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = UART2_TX_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(UART2_TX_PORT, &GPIO_InitStructure);

	/* Configure USART Rx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = UART2_RX_PIN;
	GPIO_Init(UART2_RX_PORT, &GPIO_InitStructure);

	/* USART configuration */
	USART_InitStructure.USART_BaudRate = 28800;	// 9600, 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART2, &USART_InitStructure);

	/* Enable USART */
	USART_Cmd(USART2, ENABLE);

	/* Enable the USART Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	gRingBuf2.RxCRCnt = 0;
	gFxUart2Parsing = fxUart2Parsing;
#endif /* USE_UART2 */

#ifdef	USE_UART3
	/* Enable GPIO clock */
	RCC_AHBPeriphClockCmd(UART3_TX_CLK | UART3_RX_CLK, ENABLE);

	/* Enable USART clock */
	RCC_APB1PeriphClockCmd(UART3_CLK, ENABLE);

	/* Connect PXx to USARTx_Tx */
	GPIO_PinAFConfig(UART3_TX_PORT, UART3_TX_SOURCE, UART3_TX_AF);

	/* Connect PXx to USARTx_Rx */
	GPIO_PinAFConfig(UART3_RX_PORT, UART3_RX_SOURCE, UART3_RX_AF);

	/* Configure USART Tx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = UART3_TX_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(UART3_TX_PORT, &GPIO_InitStructure);

	/* Configure USART Rx as alternate function push-pull */
	GPIO_InitStructure.GPIO_Pin = UART3_RX_PIN;
	GPIO_Init(UART3_RX_PORT, &GPIO_InitStructure);

	/* USART configuration */
	USART_InitStructure.USART_BaudRate = 28800;	// 9600, 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART3, &USART_InitStructure);

	/* Enable USART */
	USART_Cmd(USART3, ENABLE);

	/* Enable the USART Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
	gRingBuf3.RxCRCnt = 0;
#endif /* USE_UART3 */
}

void Uart_Proc(u32 mode, u32 modeChanged)
{
	PRING_BUF pRB;
	u32 dwHead, dwCount;

#ifdef	USE_UART1
	pRB = &gRingBuf1;
	while (pRB->RxCRCnt) {
		dwHead = pRB->RxHead;
		dwCount = (((dwHead + RING_BUF_SIZE) - pRB->RxTail) % RING_BUF_SIZE);
		if (0 == dwCount) {
			pRB->RxCRCnt = 0;
			break;
		}

		u8 pktBuf[RING_BUF_SIZE] = {0,};
		for (u32 i=0; i<dwCount; i++) {
			u8 ch = pRB->RxBuf[pRB->RxTail++];
			if (RING_BUF_SIZE <= pRB->RxTail) {
				pRB->RxTail = 0;
			}

			if (CHAR_CR == ch) {
				if (i) {
					if (gFxUart1Parsing) {
						gFxUart1Parsing(pktBuf, i);
					}
				}

				pRB->RxCRCnt--;
				break;
			} else {
				pktBuf[i] = ch;
			}
		}
	}
#endif /* USE_UART1 */

#ifdef	USE_UART2
	pRB = &gRingBuf2;
	while (pRB->RxCRCnt) {
		dwHead = pRB->RxHead;
		dwCount = (((dwHead + RING_BUF_SIZE) - pRB->RxTail) % RING_BUF_SIZE);
		if (0 == dwCount) {
			pRB->RxCRCnt = 0;
			break;
		}

		u8 pktBuf[RING_BUF_SIZE] = {0,};
		for (u32 i=0; i<dwCount; i++) {
			u8 ch = pRB->RxBuf[pRB->RxTail++];
			if (RING_BUF_SIZE <= pRB->RxTail) {
				pRB->RxTail = 0;
			}

			if (CHAR_CR == ch) {
				if (gFxUart2Parsing) {
					i = gFxUart2Parsing(pktBuf, i);
				}

				for (u32 j=0; j<i; j++) {
					gRingBuf3.TxBuf[gRingBuf3.TxHead++] = pktBuf[j];
					if (RING_BUF_SIZE <= gRingBuf3.TxHead) {
						gRingBuf3.TxHead = 0;
					}
				}
				if (i) {
					USART_ITConfig(USART3, USART_IT_TXE, ENABLE);
				}

				pRB->RxCRCnt--;
				break;
			} else {
				pktBuf[i] = ch;
			}
		}
	}
#endif /* USE_UART2 */

#ifdef	USE_UART3
	pRB = &gRingBuf3;
	dwHead = pRB->RxHead;
	dwCount = (((dwHead + RING_BUF_SIZE) - pRB->RxTail) % RING_BUF_SIZE);
	for (u32 i=0; i<dwCount; i++) {
		u8 ch = pRB->RxBuf[pRB->RxTail++];
		if (RING_BUF_SIZE <= pRB->RxTail) {
			pRB->RxTail = 0;
		}

		gRingBuf2.TxBuf[gRingBuf2.TxHead++] = ch;
		if (RING_BUF_SIZE <= gRingBuf2.TxHead) {
			gRingBuf2.TxHead = 0;
		}
	}
	if (dwCount) {
		USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
	}
#endif /* USE_UART3 */
}

void Uart3_Send(char *str)
{
	char ch;

	while (ch = *str++) {
		gRingBuf3.TxBuf[gRingBuf3.TxHead++] = ch;
		if (RING_BUF_SIZE <= gRingBuf3.TxHead) {
			gRingBuf3.TxHead = 0;
		}
	}
	if (gRingBuf3.TxHead != gRingBuf3.TxTail) {
		USART_ITConfig(USART3, USART_IT_TXE, ENABLE);
	}
}


#ifdef	USE_UART1
void USART1_IRQHandler(void)
{
	irqHandler(USART1, &gRingBuf1);
}
#endif /* USE_UART1 */

#ifdef	USE_UART2
void USART2_IRQHandler(void)
{
	irqHandler(USART2, &gRingBuf2);
}
#endif /* USE_UART2 */

#ifdef	USE_UART3
void USART3_IRQHandler(void)
{
	irqHandler(USART3, &gRingBuf3);
}
#endif /* USE_UART3 */


static void irqHandler(USART_TypeDef *pUSARTx, PRING_BUF pRB)
{
	/* USART in mode Tramitter -------------------------------------------------*/
	if (SET == USART_GetITStatus(pUSARTx, USART_IT_TXE)) {
		USART_SendData(pUSARTx, pRB->TxBuf[pRB->TxTail++]);
		if (RING_BUF_SIZE <= pRB->TxTail) {
			pRB->TxTail = 0;
		}
		if (pRB->TxTail == pRB->TxHead) {
			USART_ITConfig(pUSARTx, USART_IT_TXE, DISABLE);
		}
	}

	/* USART in mode Receiver --------------------------------------------------*/
	if (SET == USART_GetITStatus(pUSARTx, USART_IT_RXNE)) {
		u8 ch = USART_ReceiveData(pUSARTx);
		pRB->RxBuf[pRB->RxHead++] = ch;
		if (RING_BUF_SIZE <= pRB->RxHead) {
			pRB->RxHead = 0;
		}

		if (CHAR_CR == ch) {
			pRB->RxCRCnt++;
		}
		if (USART1 == pUSARTx) {
			/* for echo */
			if (CHAR_CR == ch) {
				fputc(CHAR_LF, NULL);
			}
			fputc(ch, NULL);
		}
	}
}

/**
* @brief  Retargets the C library printf function to the USART.
* @param  None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
	/* Place your implementation of fputc here */
	/* e.g. write a character to the USART */
#ifdef	USE_UART1
#if	0
	USART_SendData(USART1, (uint8_t)ch);
	/* Loop until transmit data register is empty */
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
#else
	gRingBuf1.TxBuf[gRingBuf1.TxHead++] = (uint8_t)ch;
	if (RING_BUF_SIZE <= gRingBuf1.TxHead) {
		gRingBuf1.TxHead = 0;
	}
	USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
#endif /* USE_UART1 */
#endif

	return ch;
}

